package be.kdg.netpresent;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Vector;
import javax.swing.ImageIcon;

public class Presentation extends UnicastRemoteObject implements
		PresentationInt {

	// Default serial ID
	private static final long serialVersionUID = 1L;
	
	// The numerical ID of the presentation.
	private int iID = 0;
	
	// User defined and descriptive presentation name.
	private String sPresName;
	
	// Password to protect the presentation being opened
	// by "unauthorized" students or other users. 
	private String sPWD;
	
	// A presentation consists of at least one through 
	// a machine-memory limited amount of slides.
	private Vector<Slide> vSlides;
	
	// Variable representing the current slide being showed.
	private int iCurrentSlide;
	
	// Variable used to synchronize the server with all clients
	// and the admin-client and vice-versa. (Timestamp)
	private long lUpdate;

	// Constructor with given ID and password but with an empty name.
	// This constructor version is deprecated but not yet removed.
	// **************************************************
	// TODO => Confirmation needed. Cleanup if confirmed.
	// **************************************************
	public Presentation(int iID, String sNewPWD ) throws java.rmi.RemoteException {
		
		this.iID = iID;
		this.sPresName = "";
		this.sPWD = sNewPWD;
		this.iCurrentSlide = 0;
		this.vSlides = new Vector<Slide>();
		this.setUpdate();
	}
	
	// Constructor with given ID, user defined name and password.
	public Presentation(int iID, String sNewPresName, String sNewPWD ) throws java.rmi.RemoteException {
		
		this.iID = iID;
		this.sPresName = sNewPresName;
		this.sPWD = sNewPWD;
		this.iCurrentSlide = 0;
		this.vSlides = new Vector<Slide>();
		this.setUpdate();
	}

	// This method checks if the password entered by a client matches the
	// password stored on creation of this presentation.
	public boolean open(String sNewPWD) throws java.rmi.RemoteException {
		return sNewPWD.equals(this.sPWD);
	}

	// Return the currently showed/dealt with...
	public int getCurrSlide() throws java.rmi.RemoteException {
		return this.iCurrentSlide;
	}
	
	// Change/update the currently showed/dealt with. Used by the admin-client
	// to start a presentation on another slide than the default slide 1. (e.g.
	// if a presentation previously was not completed and picked up again later on.)
	public void setCurrSlide(int slideNumber) throws java.rmi.RemoteException {
		this.iCurrentSlide = slideNumber;
		this.setUpdate();
	}
	
	// Change/update the currently showed/dealt with. Used to change this variable
	// in the process of presenting/moving to the next slide.
	public boolean goToNextSlide() throws java.rmi.RemoteException  {
		if (this.iCurrentSlide < this.vSlides.size()) {
			this.iCurrentSlide++;
			this.setUpdate();
			return true;
		} else {
			return false;
		}
		
	}

	// This method returns the current, to be shown slide according 
	//  to the requested slide-number.
	public SlideInt getSlide(int iSlideReq) throws java.rmi.RemoteException {
		Slide slide = vSlides.elementAt(iSlideReq);
		return slide;
	}
	
	// This method is used upon creation of the presentation to generate
	// and add new slides to the presentation made.
	public void makeSlide(ImageIcon sImage, String sImgText)
			throws java.rmi.RemoteException, IOException {

		Slide slide = new Slide(sImage, sImgText);
		vSlides.add(slide);

		this.updateThis();
	}

	// Return the presentation ID...
	public int getID() throws java.rmi.RemoteException {
		return this.iID;
	}
	
	// Return the number of slides present in this presentation...
	public int getNumberOfSlides() throws java.rmi.RemoteException {
		return this.vSlides.size();
	}
	
	// Return the user defined and descriptive name of the presentation.
	public String getPresName() throws java.rmi.RemoteException {
		return this.sPresName;
	}

	// Return the update time stamp, used in the synchronization process.
	public long getUpdate() throws RemoteException {
		return lUpdate;
	}

	// Method used to set the image content of the current slide. This
	// method calls the equally called method form the Slide class.
	public void setImg(ImageIcon image) throws java.rmi.RemoteException,
			IOException {

		int iCurrSlide = this.getCurrSlide();
		Slide sTempInst0 = this.vSlides.elementAt(iCurrSlide);
		sTempInst0.setImg(image);

		this.updateThis();
	}

	// Method used to set the test content of the current slide. This
	// method calls the equally called method form the Slide class.
	public void setText(String sNewImgText) throws java.rmi.RemoteException,
			IOException {

		int iCurrSlide = this.getCurrSlide();
		Slide sTempInst0 = this.vSlides.elementAt(iCurrSlide);
		sTempInst0.setText(sNewImgText);

		this.updateThis();
	}

	// Method used to set the question content of the current slide. This
	// method calls the equally called method form the Slide class.
	public void addQuestion(String sQuestion) throws java.rmi.RemoteException,
			IOException {

		int iCurrSlide = this.getCurrSlide();
		Slide sTempInst0 = this.vSlides.elementAt(iCurrSlide);
		sTempInst0.addQuestion(sQuestion);
		
		this.updateThis();
	}

	// Method used to set the answer content of the current slide. This
	// method calls the equally called method form the Slide class.
	public void addAnswer(int iQueNr, String sAnswer)
			throws java.rmi.RemoteException, IOException {

		int iCurrSlide = this.getCurrSlide();
		Slide sTempInst0 = this.vSlides.elementAt(iCurrSlide);
		sTempInst0.addAnswer(iQueNr, sAnswer);

		this.updateThis();
	}

	// Method to create a backup of the presentation. This method is used/called
	// each time there is a change applied to the content of this presentation.
	// This ensures integrity of the data throughout system shutdown or crashes.
	private void updateThis() {

		// Update the time stamp to indicate that changes have been made.
		this.setUpdate();
		
		// Create a uniform backup name according to the presentation ID.
		String sLeadingZeros = new String();
		FileOutputStream fosInst0;
		ObjectOutputStream oosInst0;

		if (10 > iID) {
			sLeadingZeros = "000";
		} else if ((10 <= iID) && (100 > iID)) {
			sLeadingZeros = "00";
		} else if ((100 <= iID) && (1000 > iID)) {
			sLeadingZeros = "0";
		}

		String sBackUpName = new String("Presentation_" + sLeadingZeros + iID + ".pres");

		// Store the presentation for the first time or overwrite an existing one. 
		try
		{		
			fosInst0 = new FileOutputStream(sBackUpName);
			oosInst0 = new ObjectOutputStream(fosInst0);
			
			oosInst0.writeObject(this);
			oosInst0.close();
		}
		catch (FileNotFoundException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	// This method sets the time stamp of last update, to be called at each update.
	// Used in the synchronization process of the application.
	private void setUpdate()
	{
		this.lUpdate = System.currentTimeMillis();
	}
}
